#include "dialog.h"
#include "ui_dialog.h"

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog),
    server(new QTcpServer(this))
{
    ui->setupUi(this);
    // 开启监听
    if (!server->listen(QHostAddress::Any, 8887))
    {
        ui->textBrowser->append("监听失败！");
        return;
    }

    // 连接监听信号
    connect(server, &QTcpServer::newConnection, this, &Dialog::newConnectionSlot);

    ui->textBrowser->append("监听开启成功，端口号为8887");

    // 设置数据库
    if (!setupDatabase())
    {
        ui->textBrowser->append("数据库初始化失败");
    }

    //服务器发送按钮点击事件
    connect(ui->pushButtonSend,SIGNAL(clicked()),
            this,SLOT(sendMessageSlot()));
}

Dialog::~Dialog()
{
    if (server->isListening()) {
        // 关闭监听
        server->close();
    }
    delete ui;
}

// 设置数据库连接和表创建
bool Dialog::setupDatabase()
{
    db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName("chatHistory.db");

    if (!db.open())
    {
        ui->textBrowser->append("数据库连接失败！");
        return false;
    }

    // 创建聊天记录表
    QSqlQuery query;
    if (!query.exec("CREATE TABLE  messages ( timestamp TEXT, ip TEXT, port INTEGER, message TEXT)"))
    {
        ui->textBrowser->append("创建表失败：" + query.lastError().text());
        return false;
    }

    return true;
}

// 插入聊天记录到数据库
void Dialog::insertMessageToDatabase(const QString &ip, quint16 port, const QString &message,const QString &timeStamp)
{
    QSqlQuery query;
    query.prepare("INSERT INTO messages (timestamp, ip, port, message) VALUES (:timestamp, :ip, :port, :message)");
    query.bindValue(":timestamp",timeStamp);
    query.bindValue(":ip", ip);
    query.bindValue(":port", port);
    query.bindValue(":message", message);
    if (!query.exec())
    {
        ui->textBrowser->append("插入聊天记录失败：" + query.lastError().text());
    }
}

//查询历史记录
QString Dialog::queryChatHistory()
{
    // 查询数据库中的聊天记录
    QSqlQuery query;
    if (!query.exec("SELECT * FROM messages "))
    {
        ui->textBrowser->append("查询聊天记录失败：" + query.lastError().text());
        return false;
    }
    // 清空聊天框
    ui->textBrowser->clear();
    QString history;
    // 显示聊天记录
    while (query.next())
    {
        QString timestamp = query.value("timestamp").toString();
        QString ip = query.value("ip").toString();
        quint16 port = query.value("port").toUInt();
        QString message = query.value("message").toString();

        // 显示格式化的聊天记录
        history.append(timestamp).append(" [").append(ip).append(":")
                .append(QString::number(port)).append("] ").append(message).append("\n");
    }
    ui->textBrowser->append(history);
    return history;
}

// 新的客户端连接
void Dialog::newConnectionSlot()
{
    // 获取新连接
    QTcpSocket *newClientSocket = server->nextPendingConnection();

    // 连接断开信号和槽
    connect(newClientSocket, SIGNAL(disconnected()), this, SLOT(disConnectedSlot()));
    connect(newClientSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));

    // 获取客户端IP和端口
    QString ip = newClientSocket->peerAddress().toString();
    quint16 port = newClientSocket->peerPort();

    // 显示新连接
    ip.prepend("IP:").append("PORT:").append(QString::number(port)).append("已连接");

    ui->textBrowser->append(ip);
    // 广播连接消息给除自己的所有连接的客户端
    sendMessageToClients(ip,port,newClientSocket);
    // 将新客户端添加到客户端列表中
    clients.append(newClientSocket);
}

// 客户端断开连接
void Dialog::disConnectedSlot()
{
    // 获取断开连接的客户端
    // 获取发出信号的对象
    QTcpSocket *clientSocket = qobject_cast<QTcpSocket*>(sender());

    if (clientSocket)
    {
        // 获取客户端IP地址
        QString ip = clientSocket->peerAddress().toString();
        //获取客户端端口号
        quint16 port = clientSocket->peerPort();

        // 从客户端列表中移除该连接
        clients.removeAll(clientSocket);  // 从列表中移除

        // 显示客户端断开连接的消息
        ip.append(":").append(QString::number(port)).append(" 断开连接");
        ui->textBrowser->append(ip);
        // 广播退出消息给除自己的所有连接的客户端
        sendMessageToClients(ip,port,clientSocket);

        // 关闭客户端连接
        clientSocket->close();
        clientSocket->deleteLater();  // 删除客户端对象，避免内存泄漏
    }
}

//发送信息函数
void Dialog::sendMessageToClients(const QString &message,quint16 port,QTcpSocket *clientSocket)
{
    // 向所有客户端广播消息
    for(int i = 0; i <clients.size();i++)
    {
        if(clients.at(i)->state() == QTcpSocket::ConnectedState   && clients.at(i) != clientSocket)
        {
            clients.at(i)->write(message.toUtf8());
        }
    }
}

// 读取客户端消息并处理
void Dialog::readyReadSlot()
{
    QTcpSocket *clientSocket = qobject_cast<QTcpSocket*>(sender()); // 获取发出信号的对象
    if(clientSocket)
    {
        QByteArray buffer = clientSocket->readAll();
        QString message = QString::fromUtf8(buffer);
        QString ip = clientSocket->peerAddress().toString();
        quint16 port = clientSocket->peerPort();
        // 获取当前时间戳
        QString timeStamp = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss");

        // 显示带时间戳的消息
        QString text = timeStamp;
        text.prepend("[").append("]").append("\n")
                .append(ip).append(":").append(message);
        ui->textBrowser->append(text);
        if(message == "history")
        {
            QString history = queryChatHistory();
            clientSocket->write(history.toUtf8());
        }
        else
        {
            insertMessageToDatabase(ip, port, message,timeStamp);
            // 广播消息给除自己的所有连接的客户端
            sendMessageToClients(text,port,clientSocket);
        }

    }
}

//查询历史记录槽函数
void Dialog::queryHistorySlot()
{
    queryChatHistory();
}

//服务器发送广播槽函数
void Dialog::sendMessageSlot()
{
    QString message = ui->lineEdit->text();
    QHostInfo info = QHostInfo::fromName(QHostInfo::localHostName());
    QHostAddress address = info.addresses().first();
    QString ip = address.toString();
    // 获取当前时间戳
    QString timeStamp = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss");
    // 显示带时间戳的消息
    QString text = timeStamp;
    text.prepend("[").append("]").append("\n")
            .append("服务器").append(":").append(message);
    sendMessageToClients(text,8887,NULL);
    insertMessageToDatabase(ip, 8887, message,timeStamp);
}
